<?php
class Module extends ModulesAppModel
{
    var $name = 'Module';
    CONST PUBLISHED = '1';
    CONST UNPUBLISHED = '0';
    protected $moduleCachingPrefix = "section_modules_";
    protected $moduleCachingPath;
    var $fieldProperties = array(
    
    	'name' => array('group' => array('general','index'), 'empty' => '-Select-','required'=>true,'validate'=>VALID_NOT_EMPTY, 'label' => 'Type'),
    	'title' => array('group' =>  array('general','index'),'required'=>true,'validate'=>VALID_NOT_EMPTY),
    	'section' => array('group' =>  array('general','index'),
    	'triggers' => array('onChange' => array('update' => array('order')))),
    	'status' => array(
    		'group' =>  array('general','index'),
    		'options' => array(self::PUBLISHED=>'Published',self::UNPUBLISHED=>'Unpublished')
    	),
    	'show_title' => array(
    		'group' => array('general','index'),
    		'options' => array("No", "Yes")
    	),
		'show_on_pages' => array(
			'type' => 'parent', 
			'childInfo' => array(
				'model' => 'Modules.ModuleVisibility', // @todo change the model name
				'child_group' => 'select',
				'allowMultiple' => true,
          "deleteMissing" => true
			),
			'group' => 'visibility',
    		//'fieldModifier' => 'toggleSerialized'
    	),
    	//'exceptions' => array('group' => 'visibility'),
    	'params' => array('fieldModifier' => 'toggleSerialized'),
    	'cache' => array(
    		'group' => array('advanced','index'), 
    		'options' => array('0'=>'No Cache','+10 seconds'=>'10 Seconds','+5 minutes'=>"5 minutes",'+10 minutes'=>"10 minutes",'+30 minutes'=>"30 minutes",'+1 hour'=>'1 Hour','+1 day'=>'1 Day')
    	),
    	'order'=>array('group'=> array('index','general'),'type'=>"select",'options'=>array()),
    	'style' => array('group' => 'advanced','label'=>'Class'),
    	'apply_default_class' => array('type'=>'checkbox','group' => 'advanced','label'=>'Apply default class'),
    
    );
    
   	var $hasMany = array('Modules.ModuleVisibility');
    
    function initialize()
    {
    	$this->setFieldProperties('show_on_pages', array("addMoreLabel"=>__("Add more pages")));
    	$this->moduleCachingPath = CACHE.'modules'.DS;
    	$sections = $this->_getSectionOptions();
    	$modules = $this->_getModuleOptions();
		$this->fieldProperties['section']['options'] = $sections;
		$this->fieldProperties['name']['options'] = $modules;
		$this->setFieldProperties('section',array('empty'=>__("-Select-"),'options'=>$sections,'validate'=>array('rule'=>array('inList',array_keys($sections)),'message'=>__("Please select a valid section"))));
		$this->setFieldProperties('name',array('options'=>$modules,'validate'=>array('rule'=>array('inList',array_keys($modules)),'required'=>true,'message'=>__("Please select a valid name."))));
    	//$this->setShowOnUrlProperties();
		parent::afterInitialize();
    }
    // @todo Incorrect way of converting to multi-lingual
    function afterInitialize()
    {
    	$fieldProperties = $this->fieldProperties;
    	foreach($fieldProperties as $field=>$properties)
    	{
    		if(isset($properties['options']))
    		{
	    		foreach($properties['options'] as $value=>$label)
	    		{
	    			$newOptionList[$value] = __($label);
	    		}
    			if(isset($properties['empty']))
	    		{
	    			$this->fieldProperties[$field]['empty'] = __('-Select-');
	    		}
	    		$this->fieldProperties[$field]['options'] = $newOptionList;
	    	}
	    	$newOptionList = array();
	    } 
    	parent::afterInitialize();	
    }
    
    function setModule($module)
    {
    	if(!$module)
    	{
    		return;
    	}
    	$params = $this->getModuleObject($module)->configuration;
    	$oldConfigFields = $this->getFields('group','params');
    	foreach($oldConfigFields as $oldConfigField)
    	{
    		unset($this->fieldProperties[$oldConfigField]);
    	}
    	if(!empty($params))
    	{
    		foreach($params as $field => $options)
    		{
    			$options['group'] = 'params';
    			$this->fieldProperties[$field] = $options;
    		}
    		$this->addFieldPropertiesValidationRule(array_keys($params),true);
    	}
    }
    
    function _getSectionOptions()
    {
    	foreach(cr('availableBlocks') as $block)
		{
			$blockValues[] = Inflector::humanize($block);
			$blockLabels[] = $block;
		}
		return array_combine($blockLabels, $blockValues);
    }
    
	function _getModuleOptions()
	{
		$optionsArray = array();
		
		$folders = array();
		$folders['app'] = APP.DS.'modules';
		
		foreach(Utility::getAllPlugins() as $plugin)
		{
			$folders[$plugin] = APP.'plugins'.DS.$plugin.DS.'modules';
		}
		foreach($folders as $plugin => $folder)
		{
			if(!is_dir($folder))
			{
				continue;
			}
			$folderCl = new Folder($folder);
			$contents = $folderCl->read();
			$moduleFiles = $contents[1];
			foreach($moduleFiles as $module)
			{
				//only .php file
				if(preg_match('/\w+\.php$/',$module)==false)
				continue;
				$module = str_replace('.php', '', $module);

				$module = Inflector::camelize($module);
				$moduleClName = $plugin.'.'.$module;
				if($plugin == 'app')
				{
					$moduleClName = $module;
				}
				$moduleObj = $this->getModuleObject($moduleClName);

				// ignore all system level modules
				if(!$moduleObj->systemOnly)
				{
					$optionsArray[$moduleClName] = $moduleObj->name;
				}
			}
		}
		
		return $optionsArray;
	}    
	
	function getModuleObject($moduleCl)
	{
		$file = APP.DS;
		if(strpos($moduleCl, '.'))
		{
			$tmp = explode('.', $moduleCl);
			$plugin = $tmp[0];
			$module = $tmp[1];
			$file .= 'plugins'.DS.$plugin.DS.'modules'.DS.Inflector::underscore($module).'.php';
			$moduleCl = $module;
		}
		else
		{
			$file .= 'modules'.DS.Inflector::underscore($moduleCl).'.php';
		}
		$moduleCl .= 'Module';
		require_once(MODULES_VENDORS_PATH.'giga_module.php');
		require_once($file);
		
		return new $moduleCl;
	}
	
	function beforeSave($options)
	{
		if($this->_isNew())
		{
			
		}else if($this->data[$this->alias]['id'] && isset($this->data[$this->alias]['section']))
		{
			//delete caching of old section.
			$oldSection = $this->field('section',array('id'=>$this->data[$this->alias]['id']));
			$this->clearCachedSections($oldSection);
		}
		//$this-> _formatDataToSave();		/* for 6002 - module task - shifted down from here */
		if(isset($this->data['Module']['name']))
		{
			$moduleObj = $this->getModuleObject($this->data['Module']['name']);
			if(method_exists($moduleObj, 'beforeSave'))
			{
				$this->data = $moduleObj->beforeSave($this->data);
			}
			
		}
		$this-> _formatDataToSave();	/* for 6002 - module task - shifted down to here */
		
		if(isset($this->data[$this->alias]['section']) && isset($this->data[$this->alias]['order']))
		{
			$id = null;
			if(isset($this->data[$this->alias]['id']))
			{
				$id = $this->data[$this->alias]['id'];
			}
			$order = $this->data[$this->alias]['order'];
			//add 1 to order only if it's not last.'Module.order >'=>$order
			$updateCondition = array('section'=>$this->data[$this->alias]['section'],'Module.id <>'=>$id);
			$updateCondition['Module.order >='] = $order;
			$moduleCount = $this->find('count',array('conditions'=>array('section'=>$this->data[$this->alias]['section'])));
			$this->updateAll(array('Module.order'=>'Module.order+1'),$updateCondition);
			if($order > 1)
			{
				if($moduleCount == $order)
				{
					$order +=2;
				}
			}else
			{
				$order = 0;
			}
			$this->data[$this->alias]['order'] = $order;
		}
		return parent::beforeSave($options);
	}
	
	function _formatDataToSave()
	{
		if(isset($this->data[$this->alias]['name']))
		{
			$this->setModule($this->data[$this->alias]['name']); // for setting up params
			//formatting params to save.
			$paramsFields = ClassRegistry::getObject($this->alias)->getFields('group','params');
			if(!empty($paramsFields) && is_array($paramsFields))
			{
				foreach($paramsFields as $field)
				{
					if(isset($this->data[$this->alias][$field]))
					{
						$this->data[$this->alias]['params'][$field] = $this->data[$this->alias][$field];
					}
				}
			}
		}
	}
	
	private function fixOrder($section)
	{
		$modules = $this->find('list',array('conditions'=>array('section'=>$section),'fields'=>array('id'),'order'=>'Module.order ASC'));
		$i = 1;
		foreach($modules as $moduleId)
		{
			$this->updateAll(array('Module.order'=>$i),array('Module.id'=>$moduleId));
			$i++;
		}
	}
	
	function beforeDelete($cascade)
	{
		$section = $this->field('section',array('id'=>$this->id));
		$this->clearCachedSections($section);
		return parent::beforeDelete($cascade);		
	}
	/**
	 * Module editor specific method.
	 * @param unknown_type $params
	 */
	function updateSection($params)
	{
		extract($params);
		$return  = false;
		if(in_array($section,array_keys($this->_getSectionOptions())))
		{
			$i = 1;
			foreach($orders as $moduleId)
			{
				if($this->hasAny(array('id'=>$moduleId)))
				{
					$this->id = $moduleId;
					$this->saveField('section',$section);
					$this->saveField('order',$i);
				}
				$i++;
			}
		}
		
		$return =true;
	}
		
	function afterSave($created)
	{
		$this->recursive =-1;
		GigaCache::set(array('path'=>$this->moduleCachingPath));
		$module = $this->findById($this->id);
		$section = $module['Module']['section'];
		$this->clearCachedSections($section);
		$moduleCacheKey = low($module['Module']['name'].'_'.'Module_'.$module['Module']['id']);
		GigaCache::delete($moduleCacheKey);
		// also delete cached module view file
		$moduleCacheFile = 'views'.DS.md5('mod_'.$module['Module']['id']);
		parent::afterSave($created);
		//set order as 1,2,3 etc.
		if(isset($this->data[$this->alias]['section']) && isset($this->data[$this->alias]['order']))
		{
			$this->fixOrder($this->data[$this->alias]['section']);
		}
	}
	
	function getSectionModules($section)
	{
		// @todo Set different cache files as per every action
		$conditions = array('Module.status <>'=>self::UNPUBLISHED);
		$condition1 = array('Module.section' => $section, 'Module.module_visibility_count' => 0);
		$action = GigaActionHandler::getCurrentAction();
		// prepare conditions for action specific modules
		$cacheKey = $this->getActionCacheKey($action,$section);
		$modules = null;
		GigaCache::set(array('path'=>$this->getModuleCahcePath(),'duration'=>"+3 hour"));
		$modules = GigaCache::read($cacheKey);
		if(!is_array($modules) || cr('Modules.moduleEditorMode') == true)
		{
			if(!is_dir($this->moduleCachingPath) && mkdir($this->moduleCachingPath,0777) == false)
			{
				trigger_error(__("No module directory present in cache folder"." ".CACHE),E_USER_WARNING);
			}
			
			$moduleIds = $this->ModuleVisibility->_getActionSpecificModules($action);
			
			$condition2 = array('Module.section' => $section, 'Module.id' => $moduleIds);	
			$conditions['or'] = array($condition1, $condition2);
			$order = "Module.order ASC";
			$this->recursive = -1;
			$modules = $this->find('all', compact('conditions', 'fields','order'));
			if(!$modules)
			{
				$modules = array();
			}
			GigaCache::set(array('path'=>$this->getModuleCahcePath(),'duration'=>"+3 hour"));
			GigaCache::write($cacheKey,(array)$modules);
		}
		return $modules;
	}
	
	protected function getActionCacheKey($action,$section)
	{
		$cacheKey = $this->moduleCachingPrefix;
		$cacheKey .= $section.'_';
		$cacheKey .= $action['action_id'];
		if(!isset($action['params']))
		{
			$action['params'] = array();
		}
		foreach($action['params'] as $filter => $val)
		{
				$cacheKey .= '_'.$filter.'_'.$val;
		}
		return low($cacheKey);
	}
	
	function getModuleCahcePath()
	{
		return $this->moduleCachingPath;
	}
	
	public function clearCachedSections($section)
	{
	//	echo $section;
		uses('folder');
		$regex = '.+_'.low($this->moduleCachingPrefix.$section).'.+';
		$FolderObject = new Folder($this->moduleCachingPath);
		$files = $FolderObject->find($regex);
		foreach($files as $file)
		{
			@unlink($FolderObject->pwd().DS.$file);
		}
	}
	
	function clearModuleSpecificCache($moduleName = null)
	{
		$moduleSectionList = $this->find('all',array('fields'=>array('id','section'),'conditions'=>array('Module.name'=>$moduleName),'recursive'=>-1));
		if(!empty($moduleSectionList))
		{
			foreach($moduleSectionList as $module)
			{
				$this->clearCachedSections($module['Module']['section']);
			}
		}
	}
	
	function getOrderOptions($section)
	{
		$modules = $this->find('all',array('conditions'=>array('section'=>$section),'order'=>"Module.order ASC",'recursive'=>-1));
		$options = array();
		$i = 1;
		foreach($modules as $module)
		{
			$order = $module[$this->alias]['order'];
			$options[$order] = $i.'::'.$module[$this->alias]['title'];
			$i++;
		}
		return $options;
	}
}

?>